package pl.poznan.put.cs.idss.viamdp.core.structures;

import java.util.LinkedList;
import java.util.List;

/**
 * Klasa abstrakcyjna - implementuje metody wspólne dla wszystkich typów pól.
 * 
 * @author Kornel Lewandowski
 * 
 */
public abstract class AbstractField implements IAbstractField {

	protected int positionX = -1;
	protected int positionY = -1;

	protected Map worldMap;

	protected List<Double> history = new LinkedList<Double>();

	public AbstractField(int positionX, int positionY, Map worldMap) {

		this.positionX = positionX;
		this.positionY = positionY;
		this.worldMap = worldMap;

	}

	public long getFieldPositionX() {
		return positionX;
	}

	public long getFieldPositionY() {
		return positionY;
	}

	/**
	 * Zwraca wartość nagrody w sąsiednim - lewym polu w zadanej iteracji.
	 */
	public double getLeftNeighbourReward(long iteration) {
		if (worldMap == null) {
			return 0;
		} else {
			int leftIndex = positionY - 1;
			if (leftIndex < 0) {
				leftIndex = worldMap.getSizeY() - 1;
			}
			IField left = worldMap.getFieldsArray()[positionX][leftIndex];
			if (left instanceof ForbiddenField) {
				return ForbiddenField.FORBIDDEN_VALUE;
			} else {
				return left.getReward(worldMap.getIteration() - 1);
			}
		}
	}

	/**
	 * Zwraca wartość nagrody w sąsiednim - prawym polu w zadanej iteracji.
	 */
	public double getRightNeighbourReward(long iteration) {
		if (worldMap == null) {
			return 0;
		} else {
			int rightIndex = positionY + 1;
			if (rightIndex >= worldMap.getSizeY()) {
				rightIndex = 0;
			}
			IField right = worldMap.getFieldsArray()[positionX][rightIndex];
			if (right instanceof ForbiddenField) {
				return ForbiddenField.FORBIDDEN_VALUE;
			} else {
				return right.getReward(worldMap.getIteration() - 1);
			}
		}
	}

	/**
	 * Zwraca wartość nagrody w sąsiednim - górnym polu w zadanej iteracji.
	 */
	public double getTopNeighbourReward(long iteration) {
		if (worldMap == null) {
			return 0;
		} else {
			int topIndex = positionX - 1;
			if (topIndex < 0) {
				topIndex = worldMap.getSizeX() - 1;
			}
			IField top = worldMap.getFieldsArray()[topIndex][positionY];
			if (top instanceof ForbiddenField) {
				return ForbiddenField.FORBIDDEN_VALUE;
			} else {
				return top.getReward(worldMap.getIteration() - 1);
			}
		}
	}

	/**
	 * Zwraca wartość nagrody w sąsiednim - dolnym polu w zadanej iteracji.
	 */
	public double getBottomNeighbourReward(long iteration) {
		if (worldMap == null) {
			return 0;
		} else {
			int bottomIndex = positionX + 1;
			if (bottomIndex >= worldMap.getSizeX()) {
				bottomIndex = 0;
			}
			IField bottom = worldMap.getFieldsArray()[bottomIndex][positionY];
			if (bottom instanceof ForbiddenField) {
				return ForbiddenField.FORBIDDEN_VALUE;
			} else {
				return bottom.getReward(worldMap.getIteration() - 1);
			}
		}
	}

	public void setMap(Map map) {
		this.worldMap = map;
	}

	public Map getMap() {
		return worldMap;
	}

	public List<Double> getRewardsHistory() {
		return history;
	}

}
